package com.heima.schedule.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.api.R;
import com.heima.common.contants.RedisConstants;
import com.heima.common.contants.ScheduleConstants;
import com.heima.model.schedule.dtos.Task;
import com.heima.model.schedule.pojos.Taskinfo;
import com.heima.model.schedule.pojos.TaskinfoLogs;
import com.heima.schedule.mapper.TaskinfoLogsMapper;
import com.heima.schedule.mapper.TaskinfoMapper;
import com.heima.schedule.service.TaskService;
import com.heima.utils.common.BeanHelper;
import com.heima.utils.common.JsonUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

@Service
public class TaskServiceImpl implements TaskService {
    @Autowired
    private TaskinfoMapper taskinfoMapper;
    @Autowired
    private TaskinfoLogsMapper taskinfoLogsMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Override
    public Long addTask(Task task) {
        //添加任务到DB
        boolean flag = addTaskToDb(task);
        //添加任务到Redis
        if(flag){
            addTaskToCache(task);
        }
        //返回生成的任务ID
        return task.getTaskId();
    }


    private void addTaskToCache(Task task) {
        //判断该任务是否在未来5分钟内执行，如果是，则存入redis
        //获取未来5分钟的时间
        long futureTime = DateTime.now().plusMinutes(5).getMillis();
        //获取任务的执行时间
        long executeTime = task.getExecuteTime();
        if(executeTime<=futureTime){
            //存入任务到ZSet中
            String key = RedisConstants.TASK_TOPIC_PREFIX+task.getTaskTopic();
            redisTemplate.opsForZSet().add(key, JsonUtils.toString(task),executeTime);
        }
    }

    private boolean addTaskToDb(Task task) {
        boolean flag = false;
        try {
            //添加taskinfo表
            Taskinfo taskinfo = BeanHelper.copyProperties(task,Taskinfo.class);
            taskinfo.setExecuteTime(new Date(task.getExecuteTime()));
            taskinfoMapper.insert(taskinfo);

            //把任务ID赋值给task
            task.setTaskId(taskinfo.getTaskId());

            //添加taskinfo_logs表
            TaskinfoLogs taskinfoLogs = BeanHelper.copyProperties(taskinfo,TaskinfoLogs.class);
            taskinfoLogs.setVersion(1);//初始值
            taskinfoLogs.setStatus(ScheduleConstants.SCHEDULED);
            taskinfoLogsMapper.insert(taskinfoLogs);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return flag;
    }

    @Override
    public List<Task> poll(int taskTopic) {
        //根据任务主题，取出将要执行的任务列表
        String key = RedisConstants.TASK_TOPIC_PREFIX+taskTopic;
        Set<String> taskSet = redisTemplate.opsForZSet().rangeByScore(key, 0, System.currentTimeMillis());
        List<Task> taskList = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(taskSet)){
            for(String taskJson:taskSet){
                //将taskJson转换为Task对象
                Task task = JsonUtils.toBean(taskJson, Task.class);

                //更新DB的数据
                boolean flag = updateDb(task);

                //移除缓存任务
                if(flag){
                    redisTemplate.opsForZSet().remove(key,taskJson);
                }

                taskList.add(task);
            }
        }
        return taskList;
    }

    /**
     * 更新DB任务数据
     * @param task
     * @return
     */
    private boolean updateDb(Task task) {
        boolean flag = false;
        try {
            //删除taskinfo表
            taskinfoMapper.deleteById(task.getTaskId());

            //更新taskinfo_logs表
            TaskinfoLogs taskinfoLogs = taskinfoLogsMapper.selectById(task.getTaskId());
            taskinfoLogs.setStatus(ScheduleConstants.EXECUTED);//修改为已执行
            taskinfoLogsMapper.updateById(taskinfoLogs);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return flag;
    }


    /**
     * 每隔5分钟从DB导入任务到缓存
     * cron格式： 秒 分 时 日 月 周
     *    - ：  范围   1-10  1到10秒
     *    , :   枚举， 1,10   第1秒和第10秒
     *    / :   起始间隔， 1/10  从第1秒开始，每隔10秒
     */
    @Scheduled(cron = "0 0/5 * * * ?")
    public void reloadData(){
        //查询出未来5分钟内执行的任务
        //取出未来5分钟的时间
        Date futureTime = DateTime.now().plusMinutes(5).toDate();
        QueryWrapper<Taskinfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lt("execute_time",futureTime);
        List<Taskinfo> taskinfoList = taskinfoMapper.selectList(queryWrapper);

        //导入到缓存
        for(Taskinfo taskinfo:taskinfoList){
            Task task = BeanHelper.copyProperties(taskinfo,Task.class);
            task.setExecuteTime(taskinfo.getExecuteTime().getTime());
            addTaskToCache(task);
        }
    }
}
